; void monocromatizar_inf_asm(unsigned char *src, unsigned char *dst, int h, int w, int src_row_size, int dst_row_size);
										;	RDI,				RSI,	RDX, 	RCX, 		R8,				 R9
global monocromatizar_inf_asm

section .text

%define destino_row_size qword [rbp - 8]
%define fuente_row_size qword [rbp - 16]
%define src_rest qword [rbp - 24]
%define dst_rest qword [rbp - 32]

%define mascara dword 0xFFFFFFFF
%define NULL qword 0

monocromatizar_inf_asm:
	push rbp
	mov rbp, rsp
	sub rsp,32								; para las variables locales
	push rbx
	push r11
	push r12
	push r13
	push r14
	push r15

	
	xor r12,r12
	xor r13,r13
	xor r14,r14
	xor r15,r15
	
	mov r12,rdi								; r12 --> matris fuente
	mov r13,rsi								; r13 --> matris destino
	mov r14d,edx							; r14 --> h --> alto
	mov r15d,ecx							; r15 --> w --> ancho
	
	xor edx,edx
	mov rdx,r9		 						; r9 --> dst_row_size
	sub rdx,r15					
	mov qword  destino_row_size,rdx			; en destino_row_size guardamos el ancho del padding destino
	
	xor rax,rax
	xor rbx,rbx
	xor rdx,rdx
	
	mov rax,r15
	mov rbx,3
	mul rbx
	mov rbx,r8								; r8 --> src_row_size
	sub rbx,rax
	mov qword fuente_row_size,rbx			; en fuente_row_size guardamos el ancho del padding fuente
	
	xor rax,rax
	xor rdx,rdx
	mov rax,r15
	mov rbx,4
	div rbx
	mov rax,rdx								; rax --> resto de la divicion
	mov qword dst_rest,rax					; dst_rest --> cantidad de bytes que restan recorrer en la matris de destino
	
	xor rdx,rdx
	xor rbx,rbx
	mov rax,r15
	mov rbx,3
	mul rbx
	mov rbx,12
	div rbx
	mov rax,rdx								; rax --> resto de la divicion
	mov qword src_rest,rax					; src_rest --> cantidad de bytes que restan recorrer en la matris de fuente
		
	mov rcx,r15								; rcx --> contador de columnas
	shr rcx,2								; muevo de a 4 elementos
	xor rbx,rbx								; rbx --> contador de filas
		
ciclo_filas:	
		ciclo_columnas:
			pxor xmm0,xmm0
			pxor xmm1,xmm1
			pxor xmm2,xmm2
			pxor xmm3,xmm3
			pxor xmm4,xmm4
			pxor xmm5,xmm5
			pxor xmm6,xmm6
			pxor xmm7,xmm7	

			movdqu xmm0, [r12]				; xmm0 = 16 bytes de informacion
						
			movdqa xmm3,xmm0				; xmm3 = xmm0
			movdqa xmm4,xmm0				; xmm4 = xmm0
			movdqa xmm5,xmm0				; xmm5 = xmm0
			punpcklbw xmm3, xmm7
			punpcklbw xmm4, xmm7
			punpckhbw xmm5, xmm7
			punpcklwd xmm3, xmm7			; xmm3 = | 00 | 01 | 02 | 03 | =  B  G  R  B
			punpckhwd xmm4, xmm7			; xmm4 = | 04 | 05 | 06 | 07 | =  G  R  B  G
			punpcklwd xmm5, xmm7			; xmm5 = | 08 | 09 | 0A | 0B | =  R  B  G  R

			;SET xmm0 = | blu | blu | blu | blu |
			pxor xmm0,xmm0
			mov edx, mascara
			movd xmm0, edx					; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm1,xmm0				; xmm1 = xmm0
			pand xmm1, xmm5					; xmm1 = | 0000 | blu9 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm2,xmm0				; xmm2 = xmm0
			pand xmm2, xmm4					; xmm2 = | 0000 | 0000 | blu6 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			movd xmm6, edx					; xmm6 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm6,xmm0					; xmm6 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm6, xmm3					; xmm6 = | blu0 | 0000 | 0000 | blu3 |
			paddd xmm1, xmm2				; xmm1 = | 0000 | blu9 | blu6 | 0000 |
			paddd xmm1, xmm6				; xmm1 = | blu0 | blu9 | blu6 | blu3 |
			pshufd xmm1, xmm1, 01101100b	; xmm1 = | blu0 | blu3 | blu6 | blu9 |
			
			;SET xmm0 = | gre | gre | gre | gre |
			pxor xmm0,xmm0
			pxor xmm2,xmm2
			pxor xmm6,xmm6
			mov edx, mascara
			movd xmm0, edx					; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm2,xmm0				; xmm2 = xmm0
			pand xmm2, xmm3					; xmm2 = | 0000 | gre1 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm6,xmm0				; xmm6 = xmm0
			pand xmm6, xmm5					; xmm6 = | 0000 | 0000 | greA | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			movd xmm7, edx					; xmm7 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm7,xmm0					; xmm7 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm7, xmm4					; xmm7 = | gre4 | 0000 | 0000 | gre7 |
			paddd xmm2, xmm6				; xmm2 = | 0000 | gre1 | greA | 0000 |
			paddd xmm2, xmm7				; xmm2 = | gre4 | gre1 | greA | gre7 |
			pshufd xmm2, xmm2, 10110001b	; xmm2 = | gre1 | gre4 | gre7 | greA |

			;SET xmm0 = | red | red | red | red |
			pxor xmm0,xmm0
			pxor xmm6,xmm6
			pxor xmm7,xmm7
			mov edx, mascara
			movd xmm0, edx					; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm6,xmm0				; xmm6 = xmm0
			pand xmm6, xmm4					; xmm6 = | 0000 | red5 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm7,xmm0				; xmm7 = xmm0
			pand xmm7, xmm3					; xmm7 = | 0000 | 0000 | red2 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			paddd xmm6, xmm7				; xmm6 = | 0000 | red5 | red2 | 0000 |
			pxor xmm7,xmm7					; xmm7 = | 0000 | 0000 | 0000 | 0000 |
			movd xmm7, edx					; xmm7 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm7,xmm0					; xmm7 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm7, xmm5					; xmm7 = | red8 | 0000 | 0000 | redB |
			paddd xmm6, xmm7				; xmm6 = | red8 | red5 | red2 | redB |
			pshufd xmm6, xmm6, 11000110b	; xmm6 = | red2 | red5 | red8 | redB |
			
			;xmm1 = | blu0 | blu3 | blu6 | blu9 |
			;xmm2 = | gre1 | gre4 | gre7 | greA |
			;xmm6 = | red2 | red5 | red8 | redB |
			
			packssdw xmm1, xmm1				
			packuswb xmm1, xmm1
			packssdw xmm2, xmm2				
			packuswb xmm2, xmm2
			packssdw xmm6, xmm6				
			packuswb xmm6, xmm6
			pmaxub xmm2,xmm1
			pmaxub xmm2,xmm6				; xmm2 =  | max(blu0,gre1,red2) | max(blu3,gre4,red5) | max(blu6,gre7,red8) | max(blu9,greA,redB) |
	
			movd [r13], xmm2

			lea r12, [ r12 + (4*3) ]		; incremento r12 para avanzar a los siguientes 12 elementos de la fila 
			lea r13, [ r13 + (4*1) ]		; incremento r13 para avanzar a los siguientes 4 elementos de la fila
			
			dec rcx
			cmp rcx,NULL
			jne ciclo_columnas		
						
			mov qword rax,src_rest
			lea r12, [ r12 + rax - (4*3) ]	; acomodo r12 para los ultimos bytes en caso de que la matriz no sea multiplo de 16
			mov rax,dst_rest
			lea r13, [ r13 + rax - (4*1) ]	; acomodo r13 para los ultimos bytes en caso de que la matriz no sea multiplo de 16
			
ultima_vuelta:		
			pxor xmm0,xmm0
			pxor xmm1,xmm1
			pxor xmm2,xmm2
			pxor xmm3,xmm3
			pxor xmm4,xmm4
			pxor xmm5,xmm5
			pxor xmm6,xmm6
			pxor xmm7,xmm7	
		
			movdqu xmm0, [r12]				; xmm0 = 16 bytes de informacion
						
			movdqa xmm3,xmm0				; xmm3 = xmm0
			movdqa xmm4,xmm0				; xmm4 = xmm0
			movdqa xmm5,xmm0				; xmm5 = xmm0
			punpcklbw xmm3, xmm7
			punpcklbw xmm4, xmm7
			punpckhbw xmm5, xmm7
			punpcklwd xmm3, xmm7			; xmm3 = | 00 | 01 | 02 | 03 | =  B  G  R  B
			punpckhwd xmm4, xmm7			; xmm4 = | 04 | 05 | 06 | 07 | =  G  R  B  G
			punpcklwd xmm5, xmm7			; xmm5 = | 08 | 09 | 0A | 0B | =  R  B  G  R

			;SET xmm0 = | blu | blu | blu | blu |
			pxor xmm0,xmm0
			mov edx, mascara
			movd xmm0, edx					; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm1,xmm0				; xmm1 = xmm0
			pand xmm1, xmm5					; xmm1 = | 0000 | blu9 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm2,xmm0				; xmm2 = xmm0
			pand xmm2, xmm4					; xmm2 = | 0000 | 0000 | blu6 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			movd xmm6, edx					; xmm6 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm6,xmm0					; xmm6 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm6, xmm3					; xmm6 = | blu0 | 0000 | 0000 | blu3 |
			paddd xmm1, xmm2				; xmm1 = | 0000 | blu9 | blu6 | 0000 |
			paddd xmm1, xmm6				; xmm1 = | blu0 | blu9 | blu6 | blu3 |
			pshufd xmm1, xmm1, 01101100b	; xmm1 = | blu0 | blu3 | blu6 | blu9 |
			
			;SET xmm0 = | gre | gre | gre | gre |
			pxor xmm0,xmm0
			pxor xmm2,xmm2
			pxor xmm6,xmm6
			mov edx, mascara
			movd xmm0, edx					; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm2,xmm0				; xmm2 = xmm0
			pand xmm2, xmm3					; xmm2 = | 0000 | gre1 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm6,xmm0				; xmm6 = xmm0
			pand xmm6, xmm5					; xmm6 = | 0000 | 0000 | greA | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			movd xmm7, edx					; xmm7 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm7,xmm0					; xmm7 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm7, xmm4					; xmm7 = | gre4 | 0000 | 0000 | gre7 |
			paddd xmm2, xmm6				; xmm2 = | 0000 | gre1 | greA | 0000 |
			paddd xmm2, xmm7				; xmm2 = | gre4 | gre1 | greA | gre7 |
			pshufd xmm2, xmm2, 10110001b	; xmm2 = | gre1 | gre4 | gre7 | greA |

			;SET xmm0 = | red | red | red | red |
			pxor xmm0,xmm0
			pxor xmm6,xmm6
			pxor xmm7,xmm7
			mov edx, mascara
			movd xmm0, edx					; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm6,xmm0				; xmm6 = xmm0
			pand xmm6, xmm4					; xmm6 = | 0000 | red5 | 0000 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm7,xmm0				; xmm7 = xmm0
			pand xmm7, xmm3					; xmm7 = | 0000 | 0000 | red2 | 0000 |
			pslldq xmm0,4					; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			paddd xmm6, xmm7				; xmm6 = | 0000 | red5 | red2 | 0000 |
			pxor xmm7,xmm7					; xmm7 = | 0000 | 0000 | 0000 | 0000 |
			movd xmm7, edx					; xmm7 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm7,xmm0					; xmm7 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm7, xmm5					; xmm7 = | red8 | 0000 | 0000 | redB |
			paddd xmm6, xmm7				; xmm6 = | red8 | red5 | red2 | redB |
			pshufd xmm6, xmm6, 11000110b	; xmm6 = | red2 | red5 | red8 | redB |
			
			;xmm1 = | blu0 | blu3 | blu6 | blu9 |
			;xmm2 = | gre1 | gre4 | gre7 | greA |
			;xmm6 = | red2 | red5 | red8 | redB |
			
			packssdw xmm1, xmm1				
			packuswb xmm1, xmm1
			packssdw xmm2, xmm2				
			packuswb xmm2, xmm2
			packssdw xmm6, xmm6				
			packuswb xmm6, xmm6
			pmaxub xmm2,xmm1
			pmaxub xmm2,xmm6				; xmm2 =  | max(blu0,gre1,red2) | max(blu3,gre4,red5) | max(blu,gre7,red8) | max(blu9,greA,redB) |
	
			movd [r13], xmm2

			lea r12, [ r12 + (4*3) ]		; incremento r12 para avanzar a los siguientes 12 elementos de la fila 
			lea r13, [ r13 + (4*1) ]		; incremento r13 para avanzar a los siguientes 4 elementos de la fila
	
		mov rdx,fuente_row_size
		
		lea r12, [r12 + rdx]				; seteo a r12 en la nueva fila de src
		mov rdx,destino_row_size
		lea r13, [r13 + rdx]				; seteo a r13 en la nueva fila de dst
		
		mov rcx,r15							; reseteo el contador de columnas
		shr rcx,2							; muevo de a 4 elementos

		inc rbx
		cmp rbx, r14
		jne ciclo_filas
	
fin:
	pop r15
	pop r14
	pop r13
	pop r12
	pop r11
	pop rbx
	add rsp,32
	pop rbp
	ret
